﻿/* ===============================================================================  
 * Copyright (c) 2010 Acid Frameworks
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * 
 * =============================================================================== */

using System;
using System.Collections.Generic;
using Acid.Graphics;


namespace Acid.Rendering
{
    /// <summary>
    /// The primary repository of all objects used for rendering. 
    /// </summary>
    public partial class Pack : IDisposable
    {
        /// <summary>
        /// The Rendering Device used by this Pack
        /// </summary>
        private Device       Device  { get; set; }
        
        /// <summary>
        /// The Objects housed in this Pack
        /// </summary>
        private List<object> Objects { get; set; }

        public Pack(Device device)
        {
            this.Device  = device;

            this.Objects = new List<object>();
        }

        #region Methods
        /// <summary>
        /// Creates a new Graph Object
        /// </summary>
        /// <returns>A Graph</returns>
        public Graph             CreateGraph             ()
        {
            Graph obj = new Graph(this.Device);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new RenderNode Object
        /// </summary>
        /// <returns>A Render Node</returns>
        public RenderNode        CreateRenderNode        ()
        {
            RenderNode obj = new RenderNode(this.Device);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new TextureRenderNode Object 
        /// </summary>
        /// <returns>A TextureRenderNode</returns>
        public RenderToTextureNode CreateTextureRenderNode()
        {
            RenderToTextureNode obj = new RenderToTextureNode(this.Device);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new TextureRenderNode Object with a Depth Buffer
        /// </summary>
        /// <returns>A TextureRenderNode</returns>
        public RenderToTextureNode CreateTextureRenderNode (int width, int height, Depth depth)
        {
            RenderToTextureNode obj = new RenderToTextureNode(this.Device, width, height, depth);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new Transform Object
        /// </summary>
        /// <returns>A Transform Object</returns>
        public Transform         CreateTransform         ()
        {
            Transform obj = new Transform();

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new State Object
        /// </summary>
        /// <returns>A State Object</returns>
        public State             CreateState             ()
        {
            State obj = new State();

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Create a new ViewInfo Object
        /// </summary>
        /// <returns>A ViewInfo Object</returns>
        public ViewInfo          CreateViewInfo          ()
        {
            ViewInfo obj = new ViewInfo();

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new Effect Object
        /// </summary>
        /// <returns>A Effect Object</returns>
        public Effect            CreateEffect            ()
        {
            Effect obj = new Effect(this.Device);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new Shader Object
        /// </summary>
        /// <returns>A Shader Object</returns>
        public Shader            CreateShader            ()
        {
            Shader obj = new Shader(this.Device);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Create a new Shape Object
        /// </summary>
        /// <returns>A Shape Object</returns>
        public Shape             CreateShape             ()
        {
            Shape obj = new Shape();

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new Shape Object
        /// </summary>
        /// <param name="primitives">An array of primitives to be added to this Shape</param>
        /// <returns>A Shape Object</returns>
        public Shape             CreateShape             (params Primitive [] primitives)
        {
            Shape obj = new Shape(primitives);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new Material Object
        /// </summary>
        /// <returns>A Material Object</returns>
        public Material          CreateMaterial          ()
        {
            Material obj = new Material();

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new Primitive Object
        /// </summary>
        /// <returns>A Primitive Object</returns>
        public Primitive         CreatePrimitive         ()
        {
            Primitive obj = new Primitive(this.Device);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new VertexBuffer
        /// </summary>
        /// <param name="vertexType">The Vertex Type</param>
        /// <param name="bufferUsage">The Buffer Usage</param>
        /// <returns>A VertexBuffer Object</returns>
        public VertexBuffer      CreateVertexBuffer      (Type vertexType, BufferUsage bufferUsage)
        {
            VertexBuffer obj = new VertexBuffer(this.Device, vertexType, bufferUsage);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new VertexBuffer Object
        /// </summary>
        /// <param name="declaration">The Vertex Declaration</param>
        /// <param name="bufferUsage">The Buffer Usage</param>
        /// <returns>A VertexBuffer Object</returns>
        public VertexBuffer      CreateVertexBuffer(VertexDeclaration declaration, BufferUsage bufferUsage)
        {
            VertexBuffer obj = new VertexBuffer(this.Device, declaration, bufferUsage);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new IndexBuffer Object
        /// </summary>
        /// <param name="bufferUsage">The Buffer Usage</param>
        /// <returns>A IndexBuffer Object</returns>
        public IndexBuffer       CreateIndexBuffer       (BufferUsage bufferUsage)
        {
            IndexBuffer obj = new IndexBuffer(this.Device, bufferUsage);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new Texture1D Object
        /// </summary>
        /// <param name="width">The width of this Texture</param>
        /// <param name="textureFormat">The format of this Texture</param>
        /// <returns>A Texture1D Object</returns>
        public Texture1D         CreateTexture1D         (int width, TextureFormat textureFormat)
        {
            Texture1D obj = Texture1D.Empty(this.Device, width, textureFormat);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new Texture2D Object
        /// </summary>
        /// <param name="width">The width of this Texture</param>
        /// <param name="height">The Height of this Texture</param>
        /// <param name="textureFormat">The fotmat of this Texture</param>
        /// <returns>A Texture2D Object</returns>
        public Texture2D         CreateTexture2D         (int width, int height, TextureFormat textureFormat)
        {
            Texture2D obj = Texture2D.Empty(this.Device, width, height, textureFormat);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Loads a new Texture2D from File
        /// </summary>
        /// <param name="filename">The path to this Texture.</param>
        /// <returns>A Texture2D Object</returns>
        public Texture2D         CreateTexture2D         (string filename)
        {
            Texture2D obj = Texture2D.FromFile(this.Device, filename);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new Texture3D Obejct
        /// </summary>
        /// <param name="width">The width of this Texture</param>
        /// <param name="height">The height of this Texture</param>
        /// <param name="depth">The depth of this Texture</param>
        /// <param name="textureFormat">The format of this Texture</param>
        /// <returns>A Texture3D object</returns>
        public Texture3D         CreateTexture3D         (int width, int height, int depth, TextureFormat textureFormat)
        {
            Texture3D obj = Texture3D.Empty(this.Device, width, height, depth, textureFormat);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a TextureCube Object
        /// </summary>
        /// <param name="edgeLength">The edge width of this Texture</param>
        /// <param name="textureFormat">The format of this Texture</param>
        /// <returns>A TextureCube Object</returns>
        public TextureCube       CreateTextureCube       (int edgeLength, TextureFormat textureFormat)
        {
            TextureCube obj = TextureCube.Empty(this.Device, edgeLength, textureFormat);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new ViewPort
        /// </summary>
        /// <param name="x">The x location of this ViewPort</param>
        /// <param name="y">The y location of this ViewPort</param>
        /// <param name="width">The width of this ViewPort</param>
        /// <param name="height">The height of this ViewPort</param>
        /// <param name="minZ">The minZ of this ViewPort</param>
        /// <param name="maxZ">The maxZ of this ViewPort</param>
        /// <returns>A ViewPort Object</returns>
        public ViewPort          CreateViewPort          (int x, int y, int width, int height, int minZ, int maxZ)
        {
            ViewPort obj = new ViewPort(x, y, width, height, minZ, maxZ);

            this.Objects.Add(obj);

            return obj;
        }
        /// <summary>
        /// Creates a new ViewPort
        /// </summary>
        /// <param name="x">The x location of this ViewPort</param>
        /// <param name="y">The y location of this ViewPort</param>
        /// <param name="width">The width of this ViewPort</param>
        /// <param name="height">The height of this ViewPort</param>
        /// <returns>A ViewPort Object</returns>
        public ViewPort          CreateViewPort          (int x, int y, int width, int height)
        {
            ViewPort obj = new ViewPort(x, y, width, height);

            this.Objects.Add(obj);

            return obj;
        }


        public Sampler          CreateProperty          (object value)
        {
            Sampler obj = new Sampler() { ID = Guid.NewGuid().ToString(), Value = value };

            this.Objects.Add(obj);

            return obj;
        }


        #endregion

        #region IDisposable Members

        private bool disposed = false;
 
        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    foreach (object o in this.Objects)
                    {
                        IDisposable disposible = o as IDisposable;

                        if (disposible != null)
                        {
                            disposible.Dispose();
                        }
                    }
                }

                this.disposed = true;
            }
        }
        /// <summary>
        /// Disposes of all resource objects housed in this Pack
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
        }

        ~Pack()
        {
            this.Dispose(false);
        }

        #endregion
    }
}
